/*!
 * gulp
 * $ npm install gulp gulp-ruby-sass gulp-cached gulp-uglify gulp-rename gulp-concat gulp-notify gulp-filter gulp-jshint gulp-rev-append gulp-cssnano gulp-imagemin browser-sync gulp-file-include gulp-autoprefixer del --save-dev
 */

// Load plugins
var gulp = require('gulp'), // 必须先引入gulp插件
    del = require('del'), // 文件删除
    less = require('gulp-less'), // less 编译
    sourcemaps = require('gulp-sourcemaps'), //确保本地已安装gulp-sourcemaps [cnpm install gulp-sourcemaps --save-dev]
    cached = require('gulp-cached'), // 缓存当前任务中的文件，只让已修改的文件通过管道
    uglify = require('gulp-uglify'), // js 压缩
    rename = require('gulp-rename'), // 重命名
    // concat = require('gulp-concat'), // 合并文件
    copy   = require('gulp-contrib-copy'),//不编译的文件直接copy
    notify = require('gulp-notify'), // 相当于 console.log()输出报错信息
    filter = require('gulp-filter'), // 过滤筛选指定文件
    jshint = require('gulp-jshint'), // js 语法校验
    // revMD5 = require('gulp-rev-append'), // 插入文件指纹（MD5）
    cssnano = require('gulp-cssnano'), // CSS 压缩
    imagemin = require('gulp-imagemin'), // 图片优化
    browserSync = require('browser-sync'), // 保存自动刷新
    connect = require('gulp-connect'), //热刷新(本地服务器)
    fileinclude = require('gulp-file-include'), // 可以 复制粘贴过来相同的代码
    autoprefixer = require('gulp-autoprefixer'), // 添加 CSS 浏览器前缀
    babel = require('gulp-babel'); // 编译es6
    plumber = require('gulp-plumber'), //gulp-plumber插件来忽略less编译错误
    changed = require('gulp-changed'),//只让修改的文件通过管道
    GJSDuck = require('gulp-jsduck'),//js文档生成
    gjsduck = new GJSDuck(['--out', 'mydoc']),//js文档生成
    runSequence = require('run-sequence'),   //添加版本号
    rev = require('gulp-rev'),//包括插入文件指纹等等
    revCollector = require('gulp-rev-collector');//添加版本号
    spritesmith=require('gulp.spritesmith');//生成雪碧图
//定义原代码的目录和编译压缩后的目录
var src = 'src',//源代码目录
    dist = 'dist';//编译压缩后的目录
//es6编译
// less
gulp.task('less', function () {0
    return gulp.src(src+'/Public/css/**/*.less') // 传入 less目录
        .pipe(plumber()) //忽略错误
        // `changed` 任务需要提前知道目标目录位置
		// 才能找出哪些文件是被修改过的
        .pipe(changed(dist))
        // .pipe(cached('less')) // 缓存传入文件，只让已修改的文件通过管道（第一次执行是全部通过，因为还没有记录缓存）
        // .pipe(autoprefixer('last 6 version')) // 添加 CSS 浏览器前缀，兼容最新的5个版本
        .pipe(less({
            plugins: [autoprefixer({
                browsers: ['> 1%', 'last 4 versions', 'Chrome>=38', 'Android >= 4.0', 'Firefox ESR', 'Firefox >= 36','iOS 7'],
                cascade: false, //是否美化属性值 默认：true 像这样：
                remove: false //是否去掉不必要的前缀 默认：true
            })]
        }))
        .pipe(sourcemaps.init()) //资源地图创建
        .pipe(sourcemaps.write()) //资源地图写入
        .pipe(rename({
            suffix: '.min'
        })) // 对管道里的文件流添加 .min 的重命名
        .pipe(cssnano()) // 压缩 CSS目录下，此时每个文件都有压缩（*.min.css）和未压缩(*.css)两个版本
        .pipe(gulp.dest(dist+'/Public/css')) //输出压缩的css文件
        .pipe(notify({
            message: "生成文件: <%= file.relative %> @ <%= options.date %>",
            templateOptions: {
            date: new Date().toLocaleTimeString()
          }}))
});
// css （拷贝 *.min.css，常规 CSS 则输出压缩与未压缩两个版本）
gulp.task('css', function () {
    return gulp.src(src+'/Public/css/**/*.css')
        .pipe(changed(dist))
        .pipe(cached('css'))
        // .pipe(gulp.dest(dist+'/Public/css')) // 把管道里的所有文件输出到 dist/css 目录
        .pipe(filter(['**/*', '!**/*.min.css'])) // 筛选出管道中的非 *.min.css 文件
		.pipe(autoprefixer({
            browsers: ['> 1%', 'last 4 versions', 'Chrome>=38', 'Android >= 4.0', 'Firefox ESR', 'Firefox >= 36','iOS 7'],
	        cascade: false, //是否美化属性值 默认：true 像这样：
	        //-webkit-transform: rotate(45deg);
	        //        transform: rotate(45deg);
	        remove: false //是否去掉不必要的前缀 默认：true
		}))
        .pipe(connect.reload()) //页面热刷新
        // .pipe(gulp.dest(dist+'/Public/css')) // 把处理过的 css 输出到 dist/css 目录
        .pipe(rename({
            suffix: '.min'
        }))
        .pipe(cssnano())
        .pipe(gulp.dest(dist+'/Public/css'))//输出压缩的css
        .pipe(notify({
            message: "生成文件: <%= file.relative %> @ <%= options.date %>",
            templateOptions: {
            date: new Date().toLocaleTimeString()
          }}))
});
//输出开发目录压缩的css文件
gulp.task('cssmin', function () {
    return gulp.src(src+'/Public/css/**/*.min.css')
    .pipe(changed(dist))
    .pipe(cached('css'))
    .pipe(gulp.dest(dist+'/Public/css'))//输出压缩的css
    .pipe(notify({
        message: "生成文件: <%= file.relative %> @ <%= options.date %>",
        templateOptions: {
        date: new Date().toLocaleTimeString()
      }}))

})
//生成雪碧图
gulp.task('spritesmith',function(){
    return gulp.src(src+'/Public/images/icon/**/*.{jpg,jpeg,png,gif,ico}')
        .pipe(spritesmith({
            imgName:'images/sprite.png',//保存合并后的名称
            cssName:'css/sprite.less',//保存合并后css样式的地址
            padding:15,//合并时两个图片的间距
            algorithm:'binary-tree',//注释1
            //cssTemplate:'dest/css/handlebarsStr.css'//注释2
            cssTemplate:function(data){             //如果是函数的话，这可以这样写
               var arr=[];
               width = data.spritesheet.px.width,
               height = data.spritesheet.px.height,
               url =  data.spritesheet.image,
               arr.push("@r:75rem;.icon{display:inline-block};")
    　　　　　　 data.sprites.forEach(function (sprite) {
                arr.push(
                    ".icon-"+sprite.name+
                    "{"+
                        // "background: url('"+url+"') "+
                        "background: url('../images/sprite.png?v="+Date.parse(new Date())+"')"+
                        "no-repeat "+
                        parseInt(sprite.px.offset_x)+"/@r "+parseInt(sprite.px.offset_y)+"/@r;"+
                        "background-size: "+ parseInt(width)+"/@r "+parseInt(height)+"/@r;"+
                        "width: "+parseInt(sprite.px.width)+"/@r;"+
                        "height: "+parseInt(sprite.px.height)+"/@r;"+
                    "}\n"
                );
            　 });
                return arr.join("");
            }
        }))
        .pipe(gulp.dest(src+'/Public'))
        .pipe(notify({ message: 'csssprite完成' }))
        .pipe(notify({
            message: "生成文件: <%= file.relative %> @ <%= options.date %>",
            templateOptions: {
            date: new Date().toLocaleTimeString()
          }}))
})
// styleReload （结合 watch 任务，无刷新CSS注入）
gulp.task('styleReload', ['less', 'css', 'image'], function () {
    return gulp.src([dist+'/Public/css/**/*.css'])
        .pipe(cached('style'))
        .pipe(browserSync.reload({
            stream: true
        })); // 使用无刷新 browserSync 注入 CSS
});

// script （拷贝 *.min.js，常规 js 则输出压缩与未压缩两个版本）
gulp.task('script', function () {
    return gulp.src([src+'/Public/js/**/*.js'])
        .pipe(changed(dist))
        .pipe(cached('script'))
        // 筛选出管道中的非 *.min.js 文件非es6目录文件
        .pipe(filter(['**/*', '!**/*.min.js','!**/es6/*.js']))
        .pipe(jshint(require('./package').jshintConfig))       // 进行检查（设定导入文件 可以配置在package内）
        .pipe(jshint.reporter('default'))  // 对代码进行报错提示
        .pipe(plumber()) //忽略错误
        //es6语法js文件无法直接压缩
        .pipe(rename({
            suffix: '.min'
        }))
        .pipe(uglify()) // 压缩js
        .pipe(gulp.dest(dist+'/Public/js')) //输出压缩后的js文件
        .pipe(notify({ message: 'JS压缩完成' }))
        .pipe(notify({
            message: "生成文件: <%= file.relative %> @ <%= options.date %>",
            templateOptions: {
            date: new Date().toLocaleTimeString()
          }}))
});
//输出开发目录压缩的js文件
gulp.task('scriptmin', function () {
    return gulp.src([src+'/Public/js/**/*.min.js'])
    .pipe(changed(dist))
    .pipe(cached('script'))
    .pipe(gulp.dest(dist+'/Public/js')) //输出压缩后的js文件
    .pipe(notify({
        message: "生成文件: <%= file.relative %> @ <%= options.date %>",
        templateOptions: {
        date: new Date().toLocaleTimeString()
      }}))
})
//处理es6语法压缩
gulp.task('es6', function () {
    return gulp.src([src+'/Public/js/es6/**/*.js'])
        .pipe(changed(dist))
        .pipe(cached('script'))
        .pipe(filter(['**/*', '!**/*.min.js'])) // 筛选出管道中的非 *.min.js 文件
        /**
         * 从package.json专门加载配置避免查找开销
         * 提示内容
         * 启用有关未定义和未使用变量的警告
         */
        .pipe(jshint(require('./package').jshintes6))       // 进行检查（设定导入文件 可以配置在package内）
        .pipe(jshint.reporter('default'))  // 对代码进行报错提示
        // // .pipe(jshint('.jshintrc')) // 从指定文件进行检查
        // // .pipe(jshint.reporter('default'))
        // // .pipe(concat('main.js'))
        // .pipe(connect.reload()) //页面热刷新
        //es6转码
        .pipe(babel({
            presets: ['env']
        }))
        .pipe(plumber()) //忽略错误
        //es6语法js文件无法直接压缩
        .pipe(rename({
            suffix: '.min'
        }))
        .pipe(uglify()) // 压缩js
        .pipe(gulp.dest(dist+'/Public/js')) //输出压缩后的js文件
        .pipe(notify({
            message: "生成文件: <%= file.relative %> @ <%= options.date %>",
            templateOptions: {
            date: new Date().toLocaleTimeString()
          }}))
});
// image
gulp.task('image', function () {
    return gulp.src(src+'/Public/images/**/*.{jpg,jpeg,png,gif,ico}')
        .pipe(changed(dist))
        .pipe(cached('image'))
        .pipe(filter(['**/*','!**/icon/*.png']))//除了icon文件夹全部解压出
        .pipe(imagemin({
            optimizationLevel: 3, //类型：Number  默认：3  取值范围：0-7（优化等级）
            progressive: true, //类型：Boolean 默认：false 无损压缩jpg图片
            interlaced: true, //类型：Boolean 默认：false 隔行扫描gif进行渲染
            multipass: true, //类型：Boolean 默认：false 多次优化svg直到完全优化
        }))
        // 取值范围：0-7（优化等级）,是否无损压缩jpg图片，是否隔行扫描gif进行渲染，是否多次优化svg直到完全优化
        .pipe(connect.reload()) //页面热刷新
        .pipe(gulp.dest(dist+'/Public/images'))
        .pipe(notify({
            message: "生成文件: <%= file.relative %> @ <%= options.date %>",
            templateOptions: {
            date: new Date().toLocaleTimeString()
          }}))
});

// html 编译 html 文件并复制字体
gulp.task('html', function () {
    return gulp.src([src+'/Home/**/*.html'])
        .pipe(changed(dist))
        .pipe(fileinclude()) // include html
        .pipe(connect.reload()) //页面热刷新
        .pipe(gulp.dest(dist+'/Home/'))/*输出html文件*/
        .pipe(notify({
            message: "生成文件: <%= file.relative %> @ <%= options.date %>",
            templateOptions: {
            date: new Date().toLocaleTimeString()
          }}))
});
// //img生成文件hash编码并生成 rev-manifest.json文件名对照映射
gulp.task('revImg', function(){
    return gulp.src(src+'/Public/images/**/*.png')
        .pipe(filter(['**/*','!**/icon/*.png']))//除了icon文件夹全部解压出
        .pipe(rev())
        .pipe(gulp.dest(dist+'/Public/images'))
        .pipe(rev.manifest())
        .pipe(gulp.dest(dist+'/Public/images'));
});
// //CSS生成文件hash编码并生成 rev-manifest.json文件名对照映射
gulp.task('revCss', function(){
    return gulp.src(dist+'/Public/css/**/*.css')
    .pipe(rev())
    .pipe(gulp.dest(dist+'/Public/css'))//引用的文件添加版本号
    .pipe(rev.manifest())
    .pipe(gulp.dest(dist+'/Public/css'));//输出json文件索引
   });

// //js生成文件hash编码并生成 rev-manifest.json文件名对照映射
gulp.task('revJs', function(){
    return gulp.src([dist+'/Public/js/**/*.js'])
    .pipe(filter(['**/*','!**/**/1.json']))//除了1.json
    .pipe(rev())
    .pipe(gulp.dest(dist+'/Public/js'))//引用的文件添加版本号
    .pipe(rev.manifest())
    .pipe(gulp.dest(dist+'/Public/js'));//输出json文件索引
});

 //Html更换css、js文件版本
 gulp.task('revHtml', function () {
    return gulp.src([dist+'/**/*.json', dist+'/Home/**/*.html'])  /*WEB-INF/Homes是本地html文件的路径，可自行配置*/
    .pipe(filter(['**/*','!**/**/1.json']))//除了1.json
   .pipe(revCollector())
   .pipe(gulp.dest(dist+'/Home/'));  /*Html更换css、js文件版本,WEB-INF/Homes也是和本地html文件的路径一致*/
  });
 //Html更换dev文件版本
gulp.task('dev', function (done) {
    ////需要说明的是，用gulp.run也可以实现以上所有任务的执行，
    //只是gulp.run是最大限度的并行执行这些任务，
    //而在添加版本号时需要串行执行（顺序执行）这些任务，故使用了runSequence.
    condition = false;
    runSequence(
    ['revImg'],
    ['revCss'],
    ['revJs'],
    ['revHtml'],
    done);
});

// clean 清空 生产 目录
gulp.task('clean', function () {
    return del(dist+'/**/*');
});

// build，关连执行全部编译任务
gulp.task('build', ['less', 'css', 'script', 'image','html','scriptmin','cssmin','copy'], function () {
    gulp.start('html');
});

// copy 其他不编译的文件直接copy
gulp.task('copy',  function () {
    return gulp.src(src+'/**/*.!(jpg|jpeg|png|gif|bmp|scss|less|js|html|tpl|css)')
        .pipe(copy())
        .pipe(gulp.dest(dist+'/'));
});

// default 默认任务，依赖清空dist目录和生成api文档
gulp.task('default', ['clean', 'doc'], function () {
    return gulp.start('build');
});

//doc生成javascript api文档
gulp.task('doc', function () {
    return gulp.src(src+'/Public/js/es6/*.js')
        .pipe(gjsduck.doc());
});
// watch 开启本地服务器并监听
gulp.task('watch', ['less', 'css', 'script', 'image','html'], function () {
    browserSync.init({
        //静态服务器配置
        // server: {
        //     baseDir: 'src' // 在 dist 目录下启动本地服务器环境，自动启动默认浏览器,设置服务器的根目录
        //     //index:'blink/blink.html' // 指定默认打开的文件
        // },
        //代理服务器配置
        //port:8050,  // 指定访问服务器的端口号
        proxy: "tpgulp", // 设置本地服务器的地址
        // notify: false, // 刷新不弹出提示
    });
    // 监控 html 文件，有变动则执行 html 任务
    gulp.watch(src+'/Home/**/*.html', ['html']).on('change',browserSync.reload);
    // 监控 雪碧图 文件，有变动则执行CSS注入
    gulp.watch(src+'/Public/css/**/sprite.less', ['less','styleReload']);
    // 监控 less 文件，有变动则执行less注入
    gulp.watch(src+'/Public/css/**/*.less', ['css','styleReload']);
    // 监控 CSS 文件，有变动则执行CSS注入
    gulp.watch(src+'/Public/css/**/*.css', ['styleReload']);
    // 监控 js 文件，有变动则执行 script doc任务
    gulp.watch(src+'/Public/js/**/*.js', ['script']);
    // 监控图片文件，有变动则执行 image 任务
    gulp.watch(src+'/Public/images/**/*', ['image']);
    // 监听其他不编译的文件 有变化直接copy
    gulp.watch(src+'/Public/**/*.!(jpg|jpeg|png|gif|bmp|scss|js|html)', ['copy']);
    // 监控 dist 目录下除 css 目录以外的变动（如js，图片等），则自动刷新页面
    gulp.watch([src+'/Public/**/*', src+'/Public/css/**/*']).on('change', browserSync.reload);
});
